#include "gui_progress_bar.h"
#include <stdlib.h>
#include<assert.h>
#include <stddef.h>

static void __gui_progress_bar_update(gui_spirit_t *spirit)
{
    gui_progress_bar_t *pbar = GUI_PROGRESS_BAR(spirit);
    if (pbar->fraction > 1.0f)
        pbar->fraction = 1.0f;
    if (pbar->fraction < 0)
        pbar->fraction = 0;

    int w = spirit->surface->w;
    int h = spirit->surface->h;
    uint32_t len;
    uint32_t color = pbar->front_color;

    gui_surface_rectfill(spirit->surface, 0, 0, w, h, spirit->style.background_color);

    switch (pbar->orientation)
    {
    case GUI_PROGRESS_LEFT_TO_RIGHT:
        len = (uint32_t)(pbar->fraction * w);
        gui_surface_rectfill(spirit->surface, 0, 0, len, h, color);
        break;
    case GUI_PROGRESS_RIGHT_TO_LEFT:
        len = (uint32_t)(pbar->fraction * w);
        gui_surface_rectfill(spirit->surface, w - len, 0, len, h, color);
        break;
    case GUI_PROGRESS_BOTTOM_TO_TOP:
        len = (uint32_t)(pbar->fraction * h);
        gui_surface_rectfill(spirit->surface, 0, 0, w, len, color);
        break;
    case GUI_PROGRESS_TOP_TO_BOTTOM:
        len = (uint32_t)(pbar->fraction * h);
        gui_surface_rectfill(spirit->surface, 0, h - len, w, h, color);
        break;
    default:
        break;
    }
}

gui_spirit_t *gui_progress_bar_create()
{
    gui_progress_bar_t *pbar = malloc(sizeof(gui_progress_bar_t));
    if (!pbar)
        return NULL;
    pbar->fraction = 0.0f;
    pbar->step = 0.01f;
    pbar->orientation = GUI_PROGRESS_LEFT_TO_RIGHT;
    pbar->front_color = GUI_PBAR_BAR_COLOR;

    gui_spirit_t *spirit = &pbar->spirit;
    gui_spirit_init(spirit, 0, 0, GUI_PBAR_WIDTH_DEFAULT, GUI_PBAR_HEIGHT_DEFAULT);
    gui_spirit_set_type(spirit, GUI_SPIRIT_TYPE_PBAR);

    spirit->style.font_align = GUI_ALIGN_CENTER;
    spirit->style.background_color = GUI_PBAR_BACK_COLOR;
    spirit->style.font_color = GUI_BLACK;

    spirit->show_middle = __gui_progress_bar_update;

    gui_spirit_set_surface(spirit, gui_surface_create(spirit->width, spirit->height));
    __gui_progress_bar_update(spirit);

    return spirit;
}

void gui_progress_bar_set_orientation(gui_progress_bar_t *pbar, uint32_t type)
{
    if (pbar)
    {
        if (pbar->orientation != type)
        {  
            uint32_t _type = pbar->orientation;
            pbar->orientation = type;

            switch (_type)
            {
            case GUI_PROGRESS_LEFT_TO_RIGHT:
                if (type == GUI_PROGRESS_RIGHT_TO_LEFT)
                {    
                    gui_spirit_show(&pbar->spirit);
                    return;
                }
                break;
            case GUI_PROGRESS_RIGHT_TO_LEFT:
                if (type == GUI_PROGRESS_LEFT_TO_RIGHT)
                {
                    gui_spirit_show(&pbar->spirit);
                    return;
                }
                break;
            case GUI_PROGRESS_TOP_TO_BOTTOM:
                if (type == GUI_PROGRESS_BOTTOM_TO_TOP)
                {
                    gui_spirit_show(&pbar->spirit);
                    return;
                }
                break;
            case GUI_PROGRESS_BOTTOM_TO_TOP:
                if (type == GUI_PROGRESS_TOP_TO_BOTTOM)
                {
                    gui_spirit_show(&pbar->spirit);
                    return;
                }
                break;
            default:
                return;
            }

            // hide old and refresh
            gui_spirit_hide(&pbar->spirit);
            gui_spirit_t *spirit = &pbar->spirit;
            assert(spirit);

            // change width and height
            uint32_t t=spirit->width;
            spirit->width = spirit->height;
            spirit->height = t;
            gui_spirit_reset_size(spirit,spirit->width,spirit->height);


            gui_spirit_show(&pbar->spirit);
        }
    }
}

void gui_progress_bar_set_fraction(gui_progress_bar_t *pbar, double fraction)
{
    if (pbar)
    {
        pbar->fraction = fraction;
        gui_spirit_show(&pbar->spirit);
    }
}

double gui_progress_bar_get_fraction(gui_progress_bar_t *pbar)
{
    return pbar ? pbar->fraction : 0.0f;
}

gui_progress_bar_orientation_t gui_progress_bar_get_orientation(gui_progress_bar_t *pbar)
{
    return pbar ? pbar->orientation : GUI_PROGRESS_LEFT_TO_RIGHT;
}

void gui_progress_bar_pulse(gui_progress_bar_t *pbar)
{
    if (pbar)
    {
        pbar->fraction += pbar->step;
        gui_spirit_show(&pbar->spirit);
    }
}

void gui_progress_bar_set_pulse(gui_progress_bar_t *pbar, double step)
{
    if (pbar)
    {
        pbar->step = step;
    }
}

double gui_progress_bar_get_pulse_step(gui_progress_bar_t *pbar)
{
    return pbar ? pbar->step : 0.0f;
}

void gui_progress_bar_set_text(gui_progress_bar_t *pbar, char *text)
{
    if (pbar)
    {
        gui_spirit_set_text(&pbar->spirit, (char *)text);
        gui_spirit_show(&pbar->spirit);
    }
}

const char *gui_progress_bar_get_text(gui_progress_bar_t *pbar)
{
    if (!pbar)
        return NULL;
    return pbar->spirit.text;
}
